﻿using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Xml.XPath;
using BSDS.Service.Install.Configurator.Properties;
using BSDS.Service.Utils;

namespace BSDS.Service.Install.Configurator
{
    public partial class ConfiguratorMain : Form
    {
        private const string ConfigFilename = "BSDS.Service.exe.config";

        private readonly string configFilePath;
        private readonly XDocument configuration;

        public ConfiguratorMain()
        {
            InitializeComponent();

            configFilePath = Path.Combine(Program.SourcePath, ConfigFilename);
            configuration = LoadConfigurationFile();
        }

        private void bChangeWatchFolderPath_Click(object sender, EventArgs e)
        {
            var dialog = new FolderBrowserDialog();
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                tbWatchFolderPath.Text = dialog.SelectedPath;
            }
        }

        private void bSave_Click(object sender, EventArgs e)
        {
            DateTime schedulingInterval;

            if (!DateTime.TryParseExact(tbSchedulingInterval.Text, "HH:mm:ss", CultureInfo.InvariantCulture, 
                DateTimeStyles.None,out schedulingInterval))
            {
                MessageBox.Show(Resources.SchedulingIntervalInvalidFormat);
                return;
            }

            if (!string.IsNullOrEmpty(tbWatchFolderPath.Text) && !string.IsNullOrEmpty(tbMasterKey.Text) &&
                !string.IsNullOrEmpty(tbCommandTemplate.Text) )
            {
                SetupWatchDirectory(tbWatchFolderPath.Text);

                UpdateConfiguration(tbWatchFolderPath.Text, tbCommandTemplate.Text, cbEnableTimeScheduling.Enabled,
                    schedulingInterval);

                ConfigureBingMasterKey(tbMasterKey.Text);

                RestartTheService();

                MessageBox.Show(Resources.BSDSServiceHasBeenConfigured);
            }
            else
            {
                MessageBox.Show(Resources.AllFieldsAreObligatory);
            }
        }
        
        private void ConfigureBingMasterKey(string key)
        {
            var keyFilePath = Path.Combine(Program.SourcePath, "BSDS.key");

            using (var writer = new StreamWriter(new FileStream(keyFilePath, FileMode.OpenOrCreate, FileAccess.Write)))
            {
                writer.WriteLine(key);
            }
        }

        private void RestartTheService()
        {
            var serviceName = GetConfigValue("configuration/appSettings/add[@key='serviceId']", "value");

            var controller = new ServiceController {ServiceName = serviceName};

            if (!ServiceController.GetServices().Any(sc => sc.ServiceName == serviceName))
            {
                return;
            }

            if (controller.CanStop)
            {
                controller.Stop();
            }

            var binPath = Path.Combine(Program.SourcePath, "BSDS.Service.exe");
            binPath = string.Format("\"{0}\"", binPath);

            WindowsServiceUtils.ChangeServiceConfig(serviceName, ServiceBootFlag.AutoStart, binPath);

            controller.Start();
        }

        private void UpdateConfiguration(string watchFolderPath, string commandTemplate, bool enableTimeScheduling,
            DateTime schedulingTime)
        {

            UpdateConfigFile("configuration/appSettings/add[@key='inputFolderPath']",
                            "value", watchFolderPath.Trim());

            UpdateConfigFile("configuration/appSettings/add[@key='commandTemplate']",
                             "value", commandTemplate.Trim());

            UpdateConfigFile("configuration/system.diagnostics/sharedListeners/add[@name='file']",
                             "initializeData", Path.Combine(watchFolderPath, "logs\\BSDS.logs"));

            UpdateConfigFile("configuration/appSettings/add[@key='autoExecuteCommand']",
                            "value", enableTimeScheduling.ToString());

            UpdateConfigFile("configuration/appSettings/add[@key='autoExecutionTime']",
                            "value", schedulingTime.ToString("HH:mm:ss", CultureInfo.InvariantCulture));

            configuration.Save(configFilePath);
        }

        private XDocument LoadConfigurationFile()
        {
            XDocument document;

            using (var reader = new FileStream(configFilePath, FileMode.Open))
            {
                document = XDocument.Load(reader);
            }
            return document;
        }

        private void UpdateConfigFile(string xpath, string attributeName, string newValue)
        {
            var element = configuration.XPathSelectElements(xpath).First();
            var attribute = element.Attributes(XName.Get(attributeName)).First();
            attribute.Value = newValue;
        }

        private string GetConfigValue(string xpath, string attributeName)
        {
            var element = configuration.XPathSelectElements(xpath).First();
            var attribute = element.Attributes(XName.Get(attributeName)).First();

            return attribute.Value;
        }

        private void SetupWatchDirectory(string watchFolderPath)
        {
            if (!Directory.Exists(watchFolderPath))
            {
                Directory.CreateDirectory(watchFolderPath);
            }

            var watchDirectory = new DirectoryInfo(watchFolderPath);

            watchDirectory.CreateSubdirectory("logs");
        }

        private void bClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void cbEnableTimeScheduling_CheckedChanged(object sender, EventArgs e)
        {
            tbSchedulingInterval.Enabled = cbEnableTimeScheduling.Checked;
        }
    }
}
